/*
 * Author :zhaoningbo
 * Date   :2011-8-26 09:23:31
 * Email  :zhaoningbo@hotmail.com
 * Blog   :http://zhaoningbo.iteye.com/
 */
package com.number.app.watermark;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;

import javax.imageio.ImageIO;

public class TextWaterMarker implements Serializable {

    private static final long serialVersionUID = -2399556899584967783L;

    private String srcImagePath;
    private String destImagePath;

    private double angle;
    private Font font;
    private double alpha;
    private String content;
    private String stampImagePath;

    private Point printCentralPoint;

    private double _radian;
    private Graphics2D _g2d;
    private Image _srcImage;
    private Image _stampImage;
    private BufferedImage _srcBuffImage;

    public TextWaterMarker(String srcImageFile, String destImageFile) {
        super();

        this.srcImagePath = srcImageFile;
        this.destImagePath = destImageFile;

        if (!validateSrcAndDestImageFile()) {
            // TODO: How to design here? Exception, System.err, Others?
            throw new RuntimeException("the parameters contain 'null' points.");
        }
    }

    private boolean validateSrcAndDestImageFile() {
        boolean isValid = true;
        if ((null == this.srcImagePath) || (null == this.destImagePath)) {
            isValid = false;
        }
        return isValid;
    }

    public synchronized void waterMark() throws IOException {
        this.tidyMemberVariable();

        this._srcImage = ImageIO.read(new File(this.srcImagePath));
        this._srcBuffImage = new BufferedImage(_srcImage.getWidth(null),
                this._srcImage.getHeight(null), BufferedImage.TYPE_INT_RGB);

        this._g2d = this._srcBuffImage.createGraphics();
        this.doDrawGraphics();
        this._g2d.dispose();

        FileOutputStream destOutputStream = new FileOutputStream(new File(
                this.destImagePath));

        ImageIO.write(this._srcBuffImage, "JPG", destOutputStream);

    }

    private void tidyMemberVariable() throws IOException {
        this.loadDefaultFontWhenNeaded();
        this.assignValidRadian();
        this.assignValidContent();
        this.loadDefaultPointWhenNeaded();
        this.loadDefaultSrcImageWhenNeaded();
        this.loadDefaultStampImageWhenNeaded();
    }

    private void loadDefaultFontWhenNeaded() {
        if (null == this.font) {
            this.font = new Font("宋体", Font.BOLD, 30);
        }
    }

    private void assignValidRadian() {
        this._radian = (this._radian != 0) ? this._radian : Math
                .toRadians(this.angle);
    }

    private void assignValidContent() {
        if (null == this.content) {
            this.content = "Default Content";
        }
    }

    private void loadDefaultPointWhenNeaded() {
        if (null == this.printCentralPoint) {
            this.printCentralPoint = new Point(50, 100);
        }
    }

    private void loadDefaultSrcImageWhenNeaded() throws IOException {
        this._srcImage = ImageIO.read(new File(this.srcImagePath));
        this._srcBuffImage = new BufferedImage(this._srcImage.getWidth(null),
                this._srcImage.getHeight(null), BufferedImage.TYPE_INT_RGB);

    }

    private void loadDefaultStampImageWhenNeaded() throws IOException {
        if (null != this.stampImagePath) {
            this._stampImage = ImageIO.read(new File(this.stampImagePath));
        }
    }

    private void doDrawGraphics() {

        // Anti-aliasing image.
        this._g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        // Draw the original srcImage.
        this._g2d.drawImage(this._srcImage.getScaledInstance(this._srcImage
                .getWidth(null), this._srcImage.getHeight(null),
                Image.SCALE_SMOOTH), 0, 0, null);

        // Decorate the painting brush.
        this._g2d.rotate(this._radian, this._srcBuffImage.getWidth() / 2,
                this._srcBuffImage.getHeight() / 2);
        this._g2d.setColor(Color.RED);
        this._g2d.setFont(this.font);
        this._g2d.setComposite(AlphaComposite.getInstance(
                AlphaComposite.SRC_ATOP, (float) alpha));

        if (this.isDrawImage()) {
            this._g2d.drawImage(this._stampImage, this.printCentralPoint.x,
                    this.printCentralPoint.y, null);
        } else {
            this._g2d.drawString(this.content, this.printCentralPoint.x,
                    this.printCentralPoint.y);
        }

    }

    private boolean isDrawImage() {
        return (null == this._stampImage) ? false : true;
    }

    public void setAngle(double angle) {
        this.angle = angle;
    }

    public void setSrcImageFile(String srcImageFile) {
        this.srcImagePath = srcImageFile;
    }

    public void setDestImageFile(String destImageFile) {
        this.destImagePath = destImageFile;
    }

    public void setFont(Font font) {
        this.font = font;
    }

    public void setAlpha(double alpha) {
        this.alpha = alpha;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setContentCentralPoint(Point contentCentralPoint) {
        this.printCentralPoint = contentCentralPoint;
    }

    public void setStampImagePath(String stampImagePath) {
        this.stampImagePath = stampImagePath;
    }
}
